#include "demo.h"

template <typename... Args>
using overload_cast_ = pybind11::detail::overload_cast_impl<Args...>;

class Pet {
public:
    Pet(const std::string &name) : name(name) { }
    virtual ~Pet() = default;

    void setName(const std::string &name_) { name = name_; }
    const std::string &getName() const { return name; }

    void set(int age_) { age = age_; }
    void set(const std::string &name_) { name = name_; }

private:
    std::string name;
    int age;
};

class Dog : public Pet {
public:
    Dog(const std::string &name) : Pet(name) { }

    std::string bark() const { return "woof!"; }
};

std::string say_hello(Pet * pet) {
    return "Hello, " + pet->getName(); 
}

void init_demo_module(py::module_ m) {
    //py::class_<Pet> pet(m, "Pet", py::dynamic_attr());
    //pet.def(py::init<const std::string &>())
//        .def("setName", &Pet::setName)
//        .def("getName", &Pet::getName)
    
    py::class_<Pet>(m, "Pet", py::dynamic_attr())
        .def(py::init<const std::string &>())
        .def_property("name", &Pet::getName, &Pet::setName)
        .def("set", overload_cast_<int>()(&Pet::set), "Set the pet's age")
        .def("set", overload_cast_<const std::string &>()(&Pet::set), "Set the pet's name")
        .def("__repr__",
            [](const Pet &a) {
                return "<demo.Pet named '" + a.getName() + "'>";
            });

    //py::class_<Dog>(m, "Dog", pet)
    py::class_<Dog, Pet>(m, "Dog")
        .def(py::init<const std::string &>())
        .def("bark", &Dog::bark);

    m.def("pet_store", []() { return std::unique_ptr<Pet>(new Dog("Molly")); });
    m.def("say_hello", &say_hello);
}

